home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / sd-26.zip / sdui-x11.c < prev    next >
C/C++ Source or Header  |  1992-09-09  |  43KB  |  1,366 lines

  1. #ifndef lint
  2. static char *id = "@(#)sdui-x11.c      1.10    gildea@lcs.mit.edu  07 Aug 92";
  3. static char *time_stamp = "sdui-x11.c Time-stamp: <92/08/18 19:44:34 gildea>";
  4. #endif
  5. /* 
  6.  * sdui-x11.c - SD User Interface for X11
  7.  * Copyright (c) 1990,1991,1992 Stephen Gildea and William B. Ackerman
  8.  *
  9.  * Permission to use, copy, modify, and distribute this software for
  10.  * any purpose is hereby granted without fee, provided that the above
  11.  * copyright notice and this permission notice appear in all copies.
  12.  * The authors make no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without express
  14.  * or implied warranty.
  15.  *
  16.  * By Stephen Gildea, March 1990.
  17.  * Uses the Athena Widget Set from X11 Release 4 or 5.
  18.  *
  19.  * For use with version 25 of the Sd program.
  20.  *
  21.  *  The version of this file is as shown immediately below.  This
  22.  *  string gets displayed at program startup, as the "ui" part of
  23.  *  the complete version.
  24.  */
  25.  
  26. static char *sdui_x11_version = "1.10";
  27.  
  28. /* This file defines the following functions:
  29.    uims_process_command_line
  30.    uims_version_string
  31.    uims_preinitialize
  32.    uims_add_call_to_menu
  33.    uims_finish_call_menu
  34.    uims_postinitialize
  35.    uims_get_command
  36.    uims_do_comment_popup
  37.    uims_do_outfile_popup
  38.    uims_do_getout_popup
  39.    uims_do_abort_popup
  40.    uims_do_neglect_popup
  41.    uims_do_selector_popup
  42.    uims_do_quantifier_popup
  43.    uims_do_modifier_popup
  44.    uims_do_concept_popup
  45.    uims_add_new_line
  46.    uims_reduce_line_count
  47.    uims_update_resolve_menu
  48.    uims_terminate
  49. */
  50.  
  51. #include "sd.h"
  52. #include <stdio.h>
  53. #include <X11/Intrinsic.h>
  54. #include <X11/StringDefs.h>
  55. #include <X11/Shell.h>
  56. #include <X11/Xaw/Box.h>
  57. #include <X11/Xaw/Paned.h>
  58. #include <X11/Xaw/Viewport.h>
  59. #include <X11/Xaw/Label.h>
  60. #include <X11/Xaw/List.h>
  61. #include <X11/Xaw/Dialog.h>
  62. #include <X11/Xaw/AsciiText.h>
  63.  
  64. static Widget toplevel, cmdmenu, conceptspecialmenu;
  65. static Widget conceptpopup, conceptlist;
  66. static Widget lview, callview, conceptmenu, callmenu;
  67. static Widget callbox, calltitle;
  68. static Widget statuswin, txtwin;
  69. static Widget resolvewin, resolvetitle, resolvemenu;
  70. static Widget confirmpopup, confirmlabel;
  71. static Widget choosepopup, choosebox, chooselabel, chooselist;
  72. static Widget commentpopup, commentbox, outfilepopup, outfilebox;
  73. static Widget getoutpopup, getoutbox;
  74. static Widget neglectpopup, neglectbox;
  75.  
  76. /*
  77.  * The total version string looks something like
  78.  * "1.4:db1.5:ui0.6X11"
  79.  * We return the "0.6X11" part.
  80.  */
  81.  
  82. static char version_mem[12];
  83.  
  84. extern char *
  85. uims_version_string(void)
  86. {
  87.     (void) sprintf(version_mem, "%sX11", sdui_x11_version);
  88.     return version_mem;
  89. }
  90.  
  91.  
  92. static long_boolean ui_task_in_progress = FALSE;
  93.  
  94. /*
  95.  * Since callbacks and actions can't return values, narrow the use of
  96.  * global variables with these two routines.
  97.  */
  98. static int callback_value_storage; /* used only by two routines below */
  99.  
  100. static void
  101. callback_return(int return_value)
  102. {
  103.     ui_task_in_progress = FALSE;
  104.     callback_value_storage = return_value;
  105. }
  106.  
  107. /* Serial number ensures each event generates at most one action */
  108. static unsigned long action_event_serial;
  109.  
  110. typedef enum {
  111.     inside_nothing,
  112.     inside_popup,
  113.     inside_get_command
  114. } ui_context;
  115.  
  116. /* Ensures commands aren't selected while a popup is up. */
  117. static ui_context inside_what = inside_nothing;
  118.  
  119. /*
  120.  * Modification of XtAppMainLoop that returns to the caller
  121.  * when the requested action has been done.  This technique
  122.  * allows the main program to call the user interface as a
  123.  * subroutine, whereas XtAppMainLoop assumes the other way around.
  124.  */
  125. static int
  126. read_user_gesture(XtAppContext app)
  127. {
  128.     XEvent event;
  129.  
  130.     ui_task_in_progress = TRUE;
  131.  
  132.     /* allow only new user events to generate actions */
  133.     action_event_serial = NextRequest(XtDisplay(toplevel));
  134.     /*
  135.      * ui_task_in_progress is turned off asynchronously by event
  136.      * callbacks or actions when the program request is satisfied.
  137.      */
  138.     while (ui_task_in_progress) {
  139.         XtAppNextEvent(app, &event);
  140.     XtDispatchEvent(&event);
  141.     }
  142.     inside_what = inside_nothing;
  143.     return callback_value_storage;
  144. }
  145.  
  146. /*
  147.  * Remove highlighting from any list that uims_get_command might use.
  148.  * Not necessary any more with mouse-tracking highlighting,
  149.  * but is it desirable?  Perhaps it provides more feedback.
  150.  */
  151. static void
  152. unhighlight_lists(void)
  153. {
  154.     XawListUnhighlight(cmdmenu);
  155.     XawListUnhighlight(conceptspecialmenu);
  156.     XawListUnhighlight(conceptmenu);
  157.     XawListUnhighlight(callmenu);
  158.     XawListUnhighlight(resolvemenu);
  159. }
  160.  
  161. /*
  162.  * This is the callback procedure for the menus that
  163.  * uims_get_command uses, that is, not the popups.
  164.  * Sets the external variable uims_menu_index.
  165.  */
  166.  
  167. /* ARGSUSED */
  168. static void
  169. command_or_menu_chosen(Widget w, XtPointer client_data, XtPointer call_data)
  170. {
  171.     XawListReturnStruct *item = (XawListReturnStruct *) call_data;
  172.     int menu_type = (int) client_data;
  173.  
  174.     unhighlight_lists();    /* do here in case spurious event */
  175.     if (inside_what == inside_get_command) {
  176.     uims_menu_index = item->list_index; /* extern var <- menu item no. */
  177.     callback_return(menu_type); /* return which menu */
  178.     }
  179. }
  180.  
  181. /* undo action timeout proc.  Gets called after the UNDO entry
  182.    has flashed for an appropriate amount of time. */
  183. /* ARGSUSED */
  184. static void 
  185. cmdmenu_unhighlight(XtPointer client_data, XtIntervalId *intrvl)
  186. {
  187.     XawListUnhighlight(cmdmenu);
  188. }
  189.  
  190. /* Simulates a click on the specified command menu item.
  191.    Compare with command_or_menu_chosen above. */
  192.  
  193. static void
  194. cmdmenu_action_internal(int command)
  195. {
  196.     unhighlight_lists();
  197.     /* provide visual feedback */
  198.     XawListHighlight(cmdmenu, command);
  199.     XtAppAddTimeOut(XtWidgetToApplicationContext(cmdmenu), 200,
  200.             cmdmenu_unhighlight, NULL);
  201.     uims_menu_index = command; /* extern var <- menu item no. */
  202.     callback_return(ui_command_select); /* return which menu */
  203. }
  204.  
  205. static Atom wm_delete_window;
  206. static Atom wm_protocols;
  207.  
  208. /* normally invoked only in response to a WM request */
  209.  
  210. /* ARGSUSED */
  211. static void
  212. quit_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  213. {
  214.     if (event->type == ClientMessage  &&  event->xclient.message_type == wm_protocols)
  215.     if (event->xclient.format != 32  ||  event->xclient.data.l[0] != wm_delete_window)
  216.         return;        /* some other WM_PROTOCOL */
  217.  
  218.     cmdmenu_action_internal(command_quit);
  219. }
  220.  
  221. static mode_kind visible_mode = mode_none;
  222.  
  223. /* Special action defined because it is handy to bind to MB3. */
  224.  
  225. /* ARGSUSED */
  226. static void
  227. undo_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  228. {
  229.     if (inside_what == inside_get_command) {
  230.     if (visible_mode != mode_normal)
  231.         XBell(XtDisplay(w), 0);
  232.     else {
  233.         cmdmenu_action_internal(command_undo);
  234.     }
  235.     }
  236. }
  237.  
  238.     
  239. /* popup actions */
  240.  
  241. /* ARGSUSED */
  242. static void
  243. popup_yes_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  244. {
  245.     if (event->xany.serial >= action_event_serial) {
  246.     callback_return(POPUP_ACCEPT);
  247.     }
  248. }
  249.  
  250. /* ARGSUSED */
  251. static void
  252. popup_no_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  253. {
  254.     if (event->xany.serial >= action_event_serial) {
  255.     callback_return(POPUP_DECLINE);
  256.     }
  257. }
  258.  
  259. /* ARGSUSED */
  260. static void
  261. accept_string_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  262. {
  263.     callback_return(POPUP_ACCEPT_WITH_STRING);
  264. }
  265.  
  266.  
  267. /* popup callbacks */
  268.  
  269. /* ARGSUSED */
  270. static void
  271. choose_pick(Widget w, XtPointer client_data, XtPointer call_data)
  272. {
  273.     XawListReturnStruct *item = (XawListReturnStruct *) call_data;
  274.  
  275.     if (inside_what == inside_popup) {
  276.     callback_return(item->list_index + 1); /* can't return 0 */
  277.     }
  278. }
  279.  
  280. /* ARGSUSED */
  281. static void
  282. dialog_callback(Widget w, XtPointer client_data, XtPointer call_data)
  283. {
  284.     if (inside_what == inside_popup) {
  285.     callback_return((int) client_data); /* return desired answer */
  286.     }
  287. }
  288.  
  289. static XtActionsRec actionTable[] = {
  290.     {"popup_yes", popup_yes_action},
  291.     {"popup_no", popup_no_action},
  292.     {"accept_string", accept_string_action},
  293.     {"undo", undo_action},
  294.     {"quit", quit_action}
  295. };
  296.  
  297. /* The <UnmapNotify> translations in the popups protect us from
  298.    window managers which allow the user to popdown menus explicitly.
  299.    Making <BtnUp> null is necessary to prevent Down,Motion,Up from
  300.    generating two Notify events. */
  301.  
  302. static String list_translations =
  303.     "<Motion>: Set() \n\
  304.      <LeaveWindow>: Unset() \n\
  305.      <Btn1Down>: Set()Notify() \n\
  306.      <BtnUp>: \n";
  307.  
  308. static String confirm_translations =
  309.     "<BtnDown>:    popup_yes()\n\
  310.      <LeaveWindow>: popup_no()\n\
  311.      <UnmapNotify>: popup_no()\n";
  312.  
  313. static String choose_translations =
  314.     "<LeaveWindow>: popup_no()\n\
  315.      <UnmapNotify>: popup_no()\n";
  316.  
  317. static String unmap_no_translation =
  318.     "<UnmapNotify>: popup_no()\n";
  319.  
  320. static String message_trans =
  321.     "<ClientMessage>WM_PROTOCOLS: quit()\n";
  322.  
  323. typedef struct _SdResources {
  324.     String abort_query;
  325.     String modify_format;
  326.     String modify_tag_format;
  327.     String modify_scoot_format;
  328.     String modify_line_two;
  329.     String modifications_allowed[3];
  330.     String start_list[NUM_START_SELECT_KINDS];
  331.     String cmd_list[NUM_COMMAND_KINDS];
  332.     String resolve_list[NUM_RESOLVE_COMMAND_KINDS];
  333.     String quantifier_title;
  334.     String selector_title;
  335. } SdResources;
  336.  
  337. static SdResources sd_resources;
  338.  
  339. /* General program resources */
  340.  
  341. #define MENU(name, loc, default) \
  342.     {name, "Menu", XtRString, sizeof(String), \
  343.      XtOffsetOf(SdResources, loc), XtRString, default}
  344.  
  345. static XtResource startup_resources[] = {
  346.     MENU("exit", start_list[start_select_exit], "Exit from the program"),
  347.     MENU("heads1P2P", start_list[start_select_h1p2p], "Heads 1P2P"),
  348.     MENU("sides1P2P", start_list[start_select_s1p2p], "Sides 1P2P"),
  349.     MENU("headsStart", start_list[start_select_heads_start], "Heads start"),
  350.     MENU("sidesStart", start_list[start_select_sides_start], "Sides start"),
  351.     MENU("asTheyAre", start_list[start_select_as_they_are], "Just as they are")
  352. };
  353.  
  354. static XtResource command_resources[] = {
  355.     MENU("exit", cmd_list[command_quit], "Exit the program"),
  356.     MENU("undo", cmd_list[command_undo], "Undo last call"),
  357.     MENU("abort", cmd_list[command_abort], "Abort this sequence"),
  358.     MENU("mods", cmd_list[command_allow_modification], "Allow modifications"),
  359.     MENU("comment", cmd_list[command_create_comment], "Insert a comment ..."),
  360.     MENU("outfile", cmd_list[command_change_outfile], "Change output file ..."),
  361.     MENU("getout", cmd_list[command_getout], "End this sequence ..."),
  362.     MENU("neglect", cmd_list[command_neglect], "Show neglected calls ..."),
  363.     MENU("savepic", cmd_list[command_save_pic], "Save picture"),
  364.     MENU("resolve", cmd_list[command_resolve], "Resolve ..."),
  365.     MENU("reconcile", cmd_list[command_reconcile], "Reconcile ..."),
  366.     MENU("anything", cmd_list[command_anything], "Do anything ..."),
  367.     MENU("nice", cmd_list[command_nice_setup], "Nice setup ...")
  368. };
  369.  
  370. static XtResource resolve_resources[] = {
  371.     MENU("abort", resolve_list[resolve_command_abort], "abort the search"),
  372.     MENU("find", resolve_list[resolve_command_find_another], "find another"),
  373.     MENU("next", resolve_list[resolve_command_goto_next], "go to next"),
  374.     MENU("previous", resolve_list[resolve_command_goto_previous], "go to previous"),
  375.     MENU("accept", resolve_list[resolve_command_accept], "ACCEPT current choice"),
  376.     MENU("raiseRec", resolve_list[resolve_command_raise_rec_point], "raise reconcile point"),
  377.     MENU("lowerRec", resolve_list[resolve_command_lower_rec_point], "lower reconcile point")
  378. };
  379.  
  380. static XtResource enabledmods_resources[] = {
  381.     MENU("none", modifications_allowed[0], "No call modifications enabled"),
  382.     MENU("simple", modifications_allowed[1], "Simple modifications enabled for this call"),
  383.     MENU("all", modifications_allowed[2], "All modifications enabled for this call")
  384. };
  385.  
  386. static XtResource confirm_resources[] = {
  387.     MENU("abort", abort_query, "Do you really want to abort this sequence?"),
  388.     MENU("modifyFormat", modify_format, "The \"%s\" can be replaced."),
  389.     MENU("modifyTagFormat", modify_tag_format, "The \"%s\" can be replaced with a tagging call."),
  390.     MENU("modifyScootFormat", modify_scoot_format, "The \"%s\" can be replaced with a scoot/tag (chain thru) (and scatter)."),
  391.     MENU("modifyLineTwo", modify_line_two, "Do you want to replace it?")
  392. };
  393.  
  394. static XtResource choose_resources[] = {
  395.     MENU("who", selector_title, "  Who?  "),
  396.     MENU("howMany", quantifier_title, "How many?")
  397. };
  398.  
  399. /* Fallback resources for user customization */
  400.  
  401. static String fallback_resources[] = {
  402.     "*frame.height: 600",
  403.     "*frame.internalBorderWidth: 2", /* clearer which list scrollbar with */
  404.     "*Viewport*font: fixed",    /* keep the call/concept menus narrow */
  405.     "*conceptpopup*font: fixed", /* keep the popup concept menus smaller */
  406.     "*showGrip: False",        /* no grip on Paned widgets */
  407.     "*defaultColumns: 1",    /* Lists are forced to 1 column */
  408.     "*forceColumns: True",
  409.     "*text*displayCaret: false",
  410.     "*text*scrollVertical: always",
  411.     "*text*wrap: word",
  412.     "*confirmpopup.WinGravity: 10", /* StaticGravity */
  413.     "*confirm*label.borderWidth: 2",
  414.     "*selector.choose*borderWidth: 0", /* prettier this way */
  415.     "*Dialog.value*Translations: #override <Key>Return: accept_string()\n",
  416.     "*comment.label: You can insert a comment:",
  417.     "*outfile.label: Enter new name for sequence output file:",
  418.     "*getout.label: Text to be placed at the beginning of this sequence:",
  419.     "*neglect.label: Percentage (integer) of neglected calls:",
  420.     "*abort.label: Abort",
  421.     "*ok.label: Ok",
  422.     "*abortGetout.label: Abort getout",
  423.     "*noHeader.label: No header",
  424.     "*useDefault.label: Use default",
  425.     NULL};
  426.  
  427. static char *program_name = NULL;    /* argv[0]: our name */
  428.  
  429. static XtAppContext xtcontext;
  430.  
  431. /*
  432.  * The main program calls this before doing anything else, so we can
  433.  * read the command line arguments that are relevant to the X user
  434.  * interface.  Note: If we are writing a call list, the program will
  435.  * exit before doing anything else with the user interface, but this
  436.  * must be made anyway.
  437.  */
  438. extern void
  439. uims_process_command_line(int *argcp, char *argv[])
  440. {
  441.     program_name = argv[0];
  442.     toplevel = XtAppInitialize(&xtcontext, "Sd", NULL, 0, argcp, argv,
  443.                    fallback_resources, NULL, 0);
  444. }
  445.  
  446. /*
  447.  * The main program calls this before any of the call menus are
  448.  * created, that is, before any calls to uims_add_call_to_menu
  449.  * or uims_finish_call_menu.
  450.  */
  451. extern void
  452. uims_preinitialize(void)
  453. {
  454.     Widget box, leftarea, rightarea, startupmenu, infopanes, confirmbox;
  455.     Widget cmdbox, speconsbox;
  456.     XtTranslations list_trans, unmap_no_trans;
  457.     Arg args[5];
  458.     int n;
  459.  
  460.     XtOverrideTranslations(toplevel, XtParseTranslationTable(message_trans));
  461.  
  462.     list_trans = XtParseTranslationTable(list_translations);
  463.  
  464.     n = 0;
  465.     XtSetArg(args[n], XtNorientation, XtEhorizontal); n++;
  466.     box=XtCreateManagedWidget("frame", panedWidgetClass, toplevel, args, n);
  467.  
  468.     leftarea =
  469.     XtCreateManagedWidget("leftmenus", panedWidgetClass, box, args, 0);
  470.  
  471.     rightarea =
  472.     XtCreateManagedWidget("rightmenus", panedWidgetClass, box, args, 0);
  473.  
  474.     infopanes =
  475.     XtCreateManagedWidget("infopanes", panedWidgetClass, box, args, 0);
  476.  
  477.     /* the sole purpose of this box is to keep the cmdmenu from resizing
  478.        itself.  If the window manager resizes us at startup, sizing won't
  479.        happen until after the window gets mapped, and thus the command menu
  480.        would have the shorter startup list and be the wrong size. */
  481.     cmdbox = XtCreateManagedWidget("cmdbox", panedWidgetClass, leftarea,
  482.                    args, 0);
  483.  
  484.     cmdmenu = XtCreateManagedWidget("command", listWidgetClass, cmdbox,
  485.                     args, 0);
  486.     XtOverrideTranslations(cmdmenu, list_trans);
  487.     XtGetApplicationResources(cmdmenu, (XtPointer) &sd_resources,
  488.                   command_resources,
  489.                   XtNumber(command_resources), NULL, 0);
  490.     /* This widget is never realized.  It is just a place to hang
  491.        resources off of. */
  492.     startupmenu = XtCreateWidget("startup", labelWidgetClass, cmdbox,
  493.                  args, 0);
  494.     XtGetApplicationResources(startupmenu, (XtPointer) &sd_resources,
  495.                   startup_resources,
  496.                   XtNumber(startup_resources), NULL, 0);
  497.  
  498.     /* Keeps the conceptspecialmenu from resizing itself.  See cmdbox above. */
  499.     speconsbox = XtCreateManagedWidget("speconsbx", panedWidgetClass, leftarea,
  500.                        args, 0);
  501.     conceptspecialmenu =
  502.     XtCreateManagedWidget("conceptspecial", listWidgetClass, speconsbox,
  503.                   args, 0);
  504.     XtAddCallback(conceptspecialmenu, XtNcallback,
  505.           command_or_menu_chosen, (XtPointer)ui_special_concept);
  506.     XtOverrideTranslations(conceptspecialmenu, list_trans);
  507.  
  508.     callbox = XtCreateManagedWidget("callbox", panedWidgetClass,
  509.                        rightarea, args, 0);
  510.  
  511.     calltitle = XtCreateManagedWidget("calltitle", labelWidgetClass,
  512.                      callbox, args, 0);
  513.  
  514.     n = 0;
  515.     /* Viewports may have vertical scrollbar, and it must be visible */
  516.     XtSetArg(args[n], XtNallowVert, True); n++;
  517.     XtSetArg(args[n], XtNforceBars, True); n++;
  518.     lview =
  519.     XtCreateManagedWidget("lma", viewportWidgetClass, leftarea, args, n);
  520.     callview =
  521.     XtCreateManagedWidget("rma", viewportWidgetClass, callbox, args, n);
  522.  
  523.     n = 0;
  524.     XtSetArg(args[n], XtNdefaultColumns, 1); n++;
  525.     conceptmenu =
  526.     XtCreateManagedWidget("conceptmenu", listWidgetClass, lview, args, n);
  527.     XtAddCallback(conceptmenu, XtNcallback,
  528.           command_or_menu_chosen, (XtPointer)ui_concept_select);
  529.     XtOverrideTranslations(conceptmenu, list_trans);
  530.  
  531.     callmenu =
  532.     XtCreateManagedWidget("callmenu", listWidgetClass, callview, args, n);
  533.     XtAddCallback(callmenu, XtNcallback,
  534.           command_or_menu_chosen, (XtPointer)ui_call_select);
  535.     XtOverrideTranslations(callmenu, list_trans);
  536.  
  537.     /* make it managed now so sizing gets done */
  538.     resolvewin = XtCreateManagedWidget("resolvebox", panedWidgetClass,
  539.                        rightarea, args, 0);
  540.  
  541.     resolvetitle = XtCreateManagedWidget("resolvetitle", labelWidgetClass,
  542.                      resolvewin, args, 0);
  543.  
  544.     resolvemenu = XtCreateManagedWidget("resolve", listWidgetClass,
  545.                     resolvewin, args, 0);
  546.     XtAddCallback(resolvemenu, XtNcallback,
  547.           command_or_menu_chosen, (XtPointer)ui_resolve_select);
  548.     XtOverrideTranslations(resolvemenu, list_trans);
  549.     XtGetApplicationResources(resolvemenu, (XtPointer) &sd_resources,
  550.                   resolve_resources,
  551.                   XtNumber(resolve_resources), NULL, 0);
  552.     XawListChange(resolvemenu, sd_resources.resolve_list, NUM_RESOLVE_COMMAND_KINDS,
  553.           0, TRUE);
  554.  
  555.     /* Text label is long enough to make widget wide enough.
  556.        Keyed to MAX_PRINT_LENGTH in sdutil.c.
  557.        The two extra chars are for the text area scrollbar, what a kludge. */
  558.     XtSetArg(args[0], XtNlabel,
  559.          "XX-123456789-123456789-123456789-123456789-123456789-123456789");
  560.     statuswin = XtCreateManagedWidget("enabledmods", labelWidgetClass,
  561.                       infopanes, args, 1);
  562.     XtGetApplicationResources(statuswin, (XtPointer) &sd_resources,
  563.                   enabledmods_resources,
  564.                   XtNumber(enabledmods_resources), NULL, 0);
  565.  
  566.     XtSetArg(args[0], XtNstring, ""); /* set to known string so can append */
  567.     txtwin = XtCreateManagedWidget("text", asciiTextWidgetClass, infopanes,
  568.                    args, 1);
  569.  
  570.     /* confirmation popup */
  571.  
  572.     XtAppAddActions(xtcontext, actionTable, XtNumber(actionTable));
  573.  
  574.     n = 0;
  575.     XtSetArg(args[n], XtNallowShellResize, True); n++;
  576.     confirmpopup = XtCreatePopupShell("confirmpopup", transientShellWidgetClass,
  577.                       toplevel, args, n);
  578.     XtGetApplicationResources(confirmpopup, (XtPointer) &sd_resources,
  579.                   confirm_resources, XtNumber(confirm_resources),
  580.                   NULL, 0);
  581.     XtOverrideTranslations(confirmpopup,
  582.                XtParseTranslationTable(confirm_translations));
  583.  
  584.     /* this creates a margin which makes the popup prettier */
  585.     confirmbox = XtCreateManagedWidget("confirm", boxWidgetClass,
  586.                        confirmpopup, args, 0);
  587.  
  588.     confirmlabel = XtCreateManagedWidget("label", labelWidgetClass,
  589.                      confirmbox, args, 0);
  590.  
  591.     XtRealizeWidget(confirmpopup); /* makes XtPopup faster to do this now */
  592.  
  593.     /* menu choose popup */
  594.  
  595.     n = 0;
  596.     XtSetArg(args[n], XtNallowShellResize, True); n++;
  597.     choosepopup = XtCreatePopupShell("selector", transientShellWidgetClass,
  598.                      toplevel, args, n);
  599.     XtOverrideTranslations(choosepopup,
  600.                XtParseTranslationTable(choose_translations));
  601.  
  602.     choosebox = XtCreateManagedWidget("choose", boxWidgetClass,
  603.                       choosepopup, args, 0);
  604.  
  605.     chooselabel = XtCreateManagedWidget("label", labelWidgetClass,
  606.                      choosebox, args, 0);
  607.     XtGetApplicationResources(chooselabel, (XtPointer) &sd_resources,
  608.                   choose_resources, XtNumber(choose_resources),
  609.                   NULL, 0);
  610.  
  611.     n = 0;
  612.     XtSetArg(args[n], XtNcolumnSpacing, 0); n++;
  613.     chooselist = XtCreateManagedWidget("items", listWidgetClass,
  614.                        choosebox, args, n);
  615.     XtAddCallback(chooselist, XtNcallback, choose_pick, (XtPointer)NULL);
  616.     XtOverrideTranslations(chooselist, list_trans);
  617.  
  618.     XtRealizeWidget(choosepopup);
  619.  
  620.     /* comment popup */
  621.  
  622.     n = 0;
  623.     XtSetArg(args[n], XtNallowShellResize, True); n++;
  624.     commentpopup = XtCreatePopupShell("commentpopup", transientShellWidgetClass,
  625.                       toplevel, args, n);
  626.     unmap_no_trans = XtParseTranslationTable(unmap_no_translation);
  627.     XtOverrideTranslations(commentpopup, unmap_no_trans);
  628.  
  629.     n = 0;
  630.     XtSetArg(args[n], XtNvalue, ""); n++; /* create an empty value area */
  631.     commentbox = XtCreateManagedWidget("comment", dialogWidgetClass,
  632.                        commentpopup, args, n);
  633.  
  634.     XawDialogAddButton(commentbox, "abort", dialog_callback,
  635.                (XtPointer)POPUP_DECLINE);
  636.     XawDialogAddButton(commentbox, "ok", dialog_callback,
  637.                (XtPointer)POPUP_ACCEPT_WITH_STRING);
  638.  
  639.     XtRealizeWidget(commentpopup); /* makes XtPopup faster to do this now */
  640.  
  641.  
  642.     /* outfile popup */
  643.  
  644.     n = 0;
  645.     XtSetArg(args[n], XtNallowShellResize, True); n++;
  646.     outfilepopup = XtCreatePopupShell("outfilepopup", transientShellWidgetClass,
  647.                       toplevel, args, n);
  648.     XtOverrideTranslations(outfilepopup, unmap_no_trans);
  649.  
  650.     n = 0;
  651.     XtSetArg(args[n], XtNvalue, ""); n++; /* create an empty value area */
  652.     outfilebox = XtCreateManagedWidget("outfile", dialogWidgetClass,
  653.                        outfilepopup, args, n);
  654.  
  655.     XawDialogAddButton(outfilebox, "abort", dialog_callback,
  656.                (XtPointer)POPUP_DECLINE);
  657.     XawDialogAddButton(outfilebox, "ok", dialog_callback,
  658.                (XtPointer)POPUP_ACCEPT_WITH_STRING);
  659.  
  660.     XtRealizeWidget(outfilepopup); /* makes XtPopup faster to do this now */
  661.  
  662.  
  663.     /* getout popup */
  664.  
  665.     n = 0;
  666.     XtSetArg(args[n], XtNallowShellResize, True); n++;
  667.     getoutpopup = XtCreatePopupShell("getoutpopup", transientShellWidgetClass,
  668.                       toplevel, args, n);
  669.     XtOverrideTranslations(getoutpopup, unmap_no_trans);
  670.  
  671.     n = 0;
  672.     XtSetArg(args[n], XtNvalue, ""); n++; /* create an empty value area */
  673.     getoutbox = XtCreateManagedWidget("getout", dialogWidgetClass,
  674.                        getoutpopup, args, n);
  675.  
  676.     XawDialogAddButton(getoutbox, "abortGetout", dialog_callback,
  677.                (XtPointer)POPUP_DECLINE);
  678.     XawDialogAddButton(getoutbox, "noHeader", dialog_callback,
  679.                (XtPointer)POPUP_ACCEPT);
  680.     XawDialogAddButton(getoutbox, "ok", dialog_callback,
  681.                (XtPointer)POPUP_ACCEPT_WITH_STRING);
  682.  
  683.     XtRealizeWidget(getoutpopup); /* makes XtPopup faster to do this now */
  684.  
  685.     /* neglect popup */
  686.  
  687.     n = 0;
  688.     XtSetArg(args[n], XtNallowShellResize, True); n++;
  689.     neglectpopup = XtCreatePopupShell("neglectpopup", transientShellWidgetClass,
  690.                       toplevel, args, n);
  691.     XtOverrideTranslations(neglectpopup, unmap_no_trans);
  692.  
  693.     n = 0;
  694.     XtSetArg(args[n], XtNvalue, ""); n++; /* create an empty value area */
  695.     neglectbox = XtCreateManagedWidget("neglect", dialogWidgetClass,
  696.                        neglectpopup, args, n);
  697.  
  698.     XawDialogAddButton(neglectbox, "useDefault", dialog_callback,
  699.                (XtPointer)POPUP_DECLINE);
  700.     XawDialogAddButton(neglectbox, "ok", dialog_callback,
  701.                (XtPointer)POPUP_ACCEPT_WITH_STRING);
  702.  
  703.     XtRealizeWidget(neglectpopup); /* makes XtPopup faster to do this now */
  704.  
  705.  
  706.     /* concept popup */
  707.  
  708.     n = 0;
  709.     XtSetArg(args[n], XtNallowShellResize, True); n++;
  710.     conceptpopup = XtCreatePopupShell("conceptpopup",
  711.                       transientShellWidgetClass,
  712.                       toplevel, args, n);
  713.     XtOverrideTranslations(conceptpopup,
  714.                XtParseTranslationTable(choose_translations));
  715.  
  716.     n = 0;
  717.     conceptlist = XtCreateManagedWidget("items", listWidgetClass,
  718.                     conceptpopup, args, n);
  719.     XtAddCallback(conceptlist, XtNcallback, choose_pick, (XtPointer)NULL);
  720.     XtOverrideTranslations(conceptlist, list_trans);
  721.  
  722.     XtRealizeWidget(conceptpopup);
  723. }
  724.  
  725. /*
  726.  * Because the initial width of the Viewport doesn't allow for the
  727.  * scrollbar, widen it a little.  I don't know a good way to do this,
  728.  * so I use the following kludge: set the columnspacing of the child
  729.  * list (space added to the right of the only column) to the width
  730.  * of the scrollbar.
  731.  */
  732. static void
  733. widen_viewport(Widget vw, Widget childw)
  734. {
  735.     Arg args[2];
  736.     Widget scrollbar = XtNameToWidget(vw, XtEvertical);
  737.     Dimension scrollwidth, scrollborder;
  738.  
  739.     if (!scrollbar) {
  740.     (void) fprintf(stderr, "%s warning: viewport %s has no scrollbar, will not widen\n",
  741.                program_name, XtName(vw));
  742.     return;
  743.     }
  744.  
  745.     XtSetArg(args[0], XtNwidth, &scrollwidth);
  746.     XtSetArg(args[1], XtNborderWidth, &scrollborder);
  747.     XtGetValues(scrollbar, args, 2);
  748.  
  749.     XtSetArg(args[0], XtNcolumnSpacing, scrollwidth+scrollborder);
  750.     XtSetValues(childw, args, 1);
  751. }
  752.  
  753. static void
  754. add_call_to_menu(String **menu, int call_menu_index, int menu_size, char callname[])
  755. {
  756.     if (call_menu_index == 0) {    /* first item in this menu; set it up */
  757.     *menu = (String *)XtMalloc((unsigned)(menu_size+1) * sizeof(String *));
  758.     }
  759.  
  760.     (*menu)[call_menu_index] = callname;
  761. }
  762.  
  763. static String *concept_menu_list;
  764. static int concept_menu_len;
  765.  
  766. static String *call_menu_lists[NUM_CALL_LIST_KINDS];
  767. static String call_menu_names[NUM_CALL_LIST_KINDS];
  768.  
  769. static call_list_kind visible_call_menu = call_list_none;
  770.  
  771. /*
  772.  * display the requested call menu on the screen
  773.  */
  774. static void
  775. set_call_menu(call_list_kind call_menu, call_list_kind title)
  776. {
  777.     int menu_num = (int) call_menu;
  778.     int title_num = (int) title;
  779.     Arg args[1];
  780.  
  781.     XtSetArg(args[0], XtNlabel, call_menu_names[title_num]);
  782.     XtSetValues(calltitle, args, 1);
  783.     XawListChange(callmenu, call_menu_lists[menu_num],
  784.           number_of_calls[menu_num], 0, TRUE);
  785.     visible_call_menu = call_menu==title ? call_menu : call_list_none;
  786. }
  787.  
  788. static String empty_menu[] = {NULL};
  789. static call_list_kind longest_title = call_list_empty;
  790. static int longest_title_length = 0;
  791.  
  792. /* The main program calls this after all the call menus have been created,
  793.    after all calls to uims_add_call_to_menu and uims_finish_call_menu.
  794.    This performs any final initialization required by the interface package.
  795.    It must also perform any required setup of the concept menu.  The concepts
  796.    are not presented procedurally.  Instead, they can be found in the external
  797.    array concept_descriptor_table.  The number of concepts in that list is
  798.    in our argument.  For each i, the field concept_descriptor_table[i].name
  799.    has the text that we should display for the user.
  800. */
  801.  
  802. extern void
  803. uims_postinitialize(void)
  804. {
  805.     int i;
  806.  
  807.     /* initialize our special empty call menu */
  808.     call_menu_lists[call_list_empty] = empty_menu;
  809.     number_of_calls[call_list_empty] = 0;
  810.     call_menu_names[call_list_empty] = "";
  811.  
  812.     /* fill in general concept menuu */
  813.     for (i=0; i<general_concept_size; i++)
  814.     add_call_to_menu(&concept_menu_list, i, general_concept_size,
  815.              concept_descriptor_table[i+general_concept_offset].name);
  816.  
  817.     concept_menu_len = general_concept_size;
  818.  
  819.     /*
  820.      * Before realizing, fill everything up with its normal information
  821.      * so it can be sized correctly.
  822.      */
  823.     XawListChange(cmdmenu, sd_resources.cmd_list, NUM_COMMAND_KINDS, 0, TRUE);
  824.     XawListChange(conceptspecialmenu, concept_menu_strings, 0, 0, TRUE);
  825.     XawListChange(conceptmenu, concept_menu_list, concept_menu_len, 0, TRUE);
  826.     set_call_menu (call_list_any, longest_title);
  827.     
  828.     widen_viewport(lview, conceptmenu);
  829.     widen_viewport(callview, callmenu);
  830.  
  831.     XtSetMappedWhenManaged(toplevel, FALSE);
  832.     XtRealizeWidget(toplevel);
  833.  
  834.     /* do WM_DELETE_WINDOW before map */
  835.     wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", False);
  836.     wm_protocols = XInternAtom(XtDisplay(toplevel), "WM_PROTOCOLS", False);
  837.     XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel), &wm_delete_window, 1);
  838.  
  839.     XtMapWidget(toplevel);
  840. }
  841.  
  842.  
  843. /*
  844.  * We have been given the name of one call (call number
  845.  * call_menu_index, from 0 to number_of_calls[cl]) to be added to the
  846.  * call menu cl (enumerated over the type call_list_kind.)
  847.  * The string is guaranteed to be in stable storage.
  848.  */
  849. extern void
  850. uims_add_call_to_menu(call_list_kind cl, int call_menu_index, char name[])
  851. {
  852.     int menu_num = (int) cl;
  853.  
  854.     add_call_to_menu(&call_menu_lists[menu_num], call_menu_index,
  855.              number_of_calls[menu_num], name);
  856. }
  857.  
  858.  
  859. /*
  860.  * Create a menu containing number_of_calls[cl] items, which are the
  861.  * items whose text strings were previously transmitted by the calls
  862.  * to uims_add_call_to_menu.  Use the "menu_name" argument to create a
  863.  * title line for the menu.  The string is in static storage.
  864.  * 
  865.  * This will be called once for each value in the enumeration call_list_kind.
  866.  */
  867. /* ARGSUSED */
  868. extern void
  869. uims_finish_call_menu(call_list_kind cl, char menu_name[])
  870. {
  871.     call_menu_names[cl] = menu_name;
  872.  
  873.     /* XXX - counting characters is not correct because the font
  874.        need not be fixed width.  */
  875.     if (strlen (menu_name) > longest_title_length) {
  876.     longest_title_length = strlen (menu_name);
  877.     longest_title = cl;
  878.     }
  879. }
  880.  
  881.  
  882. static void
  883. switch_from_startup_mode(void)
  884. {
  885.     XawListChange(cmdmenu, sd_resources.cmd_list, NUM_COMMAND_KINDS, 0, FALSE);
  886.     XtRemoveAllCallbacks(cmdmenu, XtNcallback);
  887.     XtAddCallback(cmdmenu, XtNcallback,
  888.           command_or_menu_chosen, (XtPointer)ui_command_select);
  889.     XawListChange(conceptspecialmenu, concept_menu_strings, 0, 0, TRUE);
  890.     XawListChange(conceptmenu, concept_menu_list, concept_menu_len, 0, TRUE);
  891. }
  892.  
  893. static void
  894. switch_to_resolve_mode(void)
  895. {
  896.     if (visible_mode == mode_startup)
  897.     switch_from_startup_mode();
  898.     XtUnmanageChild(callbox);
  899.     XtManageChild(resolvewin);
  900.  
  901.     visible_mode = mode_resolve;
  902. }
  903.  
  904. static int visible_modifications = -1;
  905.  
  906. extern uims_reply
  907. uims_get_command(mode_kind mode, call_list_kind call_menu, int modifications_flag)
  908. {
  909.     Arg args[1];
  910.  
  911.     /* Update the text area */
  912.     XawTextEnableRedisplay(txtwin);
  913.  
  914.     if (visible_modifications != modifications_flag) {
  915.     XtSetArg(args[0], XtNlabel,
  916.          sd_resources.modifications_allowed[modifications_flag]);
  917.     XtSetValues(statuswin, args, 1);
  918.     visible_modifications = modifications_flag;
  919.     }
  920.  
  921.     switch (mode) {
  922.       case mode_startup:
  923.     if (visible_mode != mode_startup) {
  924.         XtUnmanageChild(resolvewin); /* managed at startup, too */
  925.         XtManageChild(callbox); /* nec if mode_resolve now */
  926.         XawListChange(cmdmenu, sd_resources.start_list,
  927.               NUM_START_SELECT_KINDS, 0, FALSE);
  928.         XawListChange(conceptspecialmenu, empty_menu, 0, 0, FALSE);
  929.         XawListChange(conceptmenu, empty_menu, 0, 0, FALSE);
  930.         set_call_menu (call_list_empty, call_list_empty);
  931.         XtRemoveAllCallbacks(cmdmenu, XtNcallback);
  932.         XtAddCallback(cmdmenu, XtNcallback,
  933.               command_or_menu_chosen, (XtPointer)ui_start_select);
  934.         visible_mode = mode_startup;
  935.     }
  936.     break;
  937.  
  938.       case mode_resolve:
  939.     if (visible_mode != mode_resolve)
  940.         switch_to_resolve_mode();
  941.     break;
  942.  
  943.       case mode_normal:
  944.     if (visible_mode != mode_normal) {
  945.         if (visible_mode == mode_resolve) {
  946.         XtUnmanageChild(resolvewin);
  947.         XtManageChild(callbox);
  948.         } else if (visible_mode == mode_startup) {
  949.         switch_from_startup_mode();
  950.         }
  951.         visible_mode = mode_normal;
  952.         visible_call_menu = call_list_none; /* no call menu visible */
  953.     }
  954.     if (visible_call_menu != call_menu)
  955.         set_call_menu (call_menu, call_menu);
  956.     break;
  957.     case mode_none:
  958.     /* this should never happen */
  959.     break;
  960.     }
  961.  
  962.     inside_what = inside_get_command;
  963.     return (uims_reply)read_user_gesture(xtcontext);
  964. }
  965.  
  966.  
  967. static void
  968. position_near_mouse(Widget popupshell)
  969. {
  970.     Arg args[3];
  971.     Window root, child;
  972.     int n;
  973.     int x, y, max_x, max_y;
  974.     int winx, winy;
  975.     Dimension width, height, border;
  976.     unsigned int mask;
  977.  
  978.     /* much of this is copied from CenterWidgetOnPoint in Xaw/TextPop.c,
  979.        which should be a publicly-callable function anyway. */
  980.  
  981.     n = 0;
  982.     XtSetArg(args[n], XtNwidth, &width); n++;
  983.     XtSetArg(args[n], XtNheight, &height); n++;
  984.     XtSetArg(args[n], XtNborderWidth, &border); n++;
  985.     XtGetValues(popupshell, args, n);
  986.  
  987.     /* be sure popup is realized before calling XtWindow on it */
  988.     XtRealizeWidget(popupshell);
  989.  
  990.     XQueryPointer(XtDisplay(popupshell), XtWindow(popupshell),
  991.           &root, &child, &x, &y, &winx, &winy, &mask);
  992.     max_x = WidthOfScreen(XtScreen(popupshell)) - width;
  993.     max_y = HeightOfScreen(XtScreen(popupshell)) - height;
  994.  
  995.     width += 2 * border;
  996.     height += 2 * border;
  997.     
  998.     x -= ( (Position) width/2 );
  999.     if (x < 0) x = 0;
  1000.     if (x > max_x) x = max_x;
  1001.     
  1002.     y -= ( (Position) height/2 );
  1003.     if (y < 0) y = 0;
  1004.     if ( y > max_y ) y = max_y;
  1005.  
  1006.     n = 0;
  1007.     XtSetArg(args[n], XtNx, (Position)x); n++;
  1008.     XtSetArg(args[n], XtNy, (Position)y); n++;
  1009.     XtSetValues(popupshell, args, n);
  1010. }
  1011.  
  1012.  
  1013. static int
  1014. do_popup(Widget popup_shell)
  1015. {
  1016.     int value;
  1017.     Display *display = XtDisplay(popup_shell);
  1018.     XEvent event;
  1019.     
  1020.     position_near_mouse(popup_shell);
  1021.     XtPopup(popup_shell, XtGrabNone);
  1022.     inside_what = inside_popup;
  1023.     value = read_user_gesture(xtcontext);
  1024.     XtPopdown(popup_shell);
  1025.     /*
  1026.      * Make sure we know the popup is popped down,
  1027.      * so we are free to resize it for the next popup.
  1028.      * (This would be a problem when there are two popups in a row.)
  1029.      */
  1030.     do {
  1031.     XMaskEvent(display, StructureNotifyMask, &event);
  1032.     XtDispatchEvent(&event);
  1033.     } while (event.type != ReparentNotify);
  1034.     return value;
  1035. }    
  1036.  
  1037. static int
  1038. get_popup_string(Widget popup, Widget dialog, char dest[])
  1039. {
  1040.     int value;
  1041.  
  1042.     value = do_popup(popup);
  1043.     if (value == POPUP_ACCEPT_WITH_STRING)
  1044.     (void) strcpy(dest, XawDialogGetValueString(dialog));
  1045.     return value;
  1046. }
  1047.  
  1048.  
  1049. extern int
  1050. uims_do_comment_popup(char dest[])
  1051. {
  1052.     return get_popup_string(commentpopup, commentbox, dest);
  1053. }
  1054.  
  1055.  
  1056. extern int
  1057. uims_do_outfile_popup(char dest[])
  1058. {
  1059.     return get_popup_string(outfilepopup, outfilebox, dest);
  1060. }
  1061.  
  1062.  
  1063. extern int
  1064. uims_do_getout_popup(char dest[])
  1065. {
  1066.     return get_popup_string(getoutpopup, getoutbox, dest);
  1067. }
  1068.  
  1069.  
  1070. extern int
  1071. uims_do_neglect_popup(char dest[])
  1072. {
  1073.     return get_popup_string(neglectpopup, neglectbox, dest);
  1074. }
  1075.  
  1076.  
  1077. static int
  1078. confirm(String question)
  1079. {
  1080.     Arg args[1];
  1081.  
  1082.     XtSetArg(args[0], XtNlabel, question);
  1083.     XtSetValues(confirmlabel, args, 1);
  1084.     return do_popup(confirmpopup);
  1085. }
  1086.  
  1087.  
  1088. extern int
  1089. uims_do_abort_popup(void)
  1090. {
  1091.     return confirm(sd_resources.abort_query);
  1092. }
  1093.  
  1094.  
  1095. extern int
  1096. uims_do_modifier_popup(char callname[], modify_popup_kind kind)
  1097. {
  1098.    char modifier_question[150];
  1099.    char *line_format = "Internal error: unknown modifier kind.";
  1100.  
  1101.    switch (kind) {
  1102.      case modify_popup_any:
  1103.        line_format = sd_resources.modify_format;
  1104.        break;
  1105.      case modify_popup_only_tag:
  1106.        line_format = sd_resources.modify_tag_format;
  1107.        break;
  1108.      case modify_popup_only_scoot:
  1109.        line_format = sd_resources.modify_scoot_format;
  1110.        break;
  1111.    }
  1112.    (void) sprintf(modifier_question, line_format, callname);
  1113.    if (strlen(sd_resources.modify_line_two)) {
  1114.        (void) strcat(modifier_question, "\n");
  1115.        (void) strcat(modifier_question, sd_resources.modify_line_two);
  1116.    }
  1117.    return confirm(modifier_question);
  1118. }
  1119.  
  1120.  
  1121. /*
  1122.  * Make sure any requested changes have appeared on the screen.
  1123.  * This function only works in the limited domain that it is being
  1124.  * used in here.
  1125.  */
  1126. static void
  1127. update_display(Widget w)
  1128. {
  1129.     XEvent event;
  1130.     Display *display = XtDisplay(w);
  1131.  
  1132.     /* make sure all Expose events that are going to arrive are here now */
  1133.     XSync(display, False);
  1134.     while (XCheckMaskEvent(display, ExposureMask, &event))
  1135.     XtDispatchEvent(&event);
  1136.     XFlush(display);
  1137. }
  1138.  
  1139. extern void
  1140. uims_update_resolve_menu(char *title)
  1141. {
  1142.     Arg args[1];
  1143.  
  1144.     XtSetArg(args[0], XtNlabel, title);
  1145.     XtSetValues(resolvetitle, args, 1);
  1146.     switch_to_resolve_mode();
  1147.     update_display(resolvetitle);
  1148. }
  1149.  
  1150.  
  1151. static int
  1152. choose_popup(String label, String names[])
  1153. {
  1154.     Arg args[2];
  1155.     Dimension labelwidth, listwidth;
  1156.     Dimension listintwid;
  1157.     Dimension stdlistintwid = 4;
  1158.  
  1159.     XtSetArg(args[0], XtNlabel, label);
  1160.     XtSetValues(chooselabel, args, 1);
  1161.     /* we clobber this each time */
  1162.     XtSetArg(args[0], XtNinternalWidth, stdlistintwid);
  1163.     XtSetValues(chooselist, args, 1);
  1164.  
  1165.     XawListChange(chooselist, names, 0, 0, TRUE);
  1166.  
  1167.     /* set the width of the box to the width of the widest child */
  1168.  
  1169.     XtSetArg(args[0], XtNwidth, &labelwidth);
  1170.     XtGetValues(chooselabel, args, 1);
  1171.  
  1172.     XtSetArg(args[0], XtNwidth, &listwidth);
  1173.     XtSetArg(args[1], XtNinternalWidth, &listintwid);
  1174.     XtGetValues(chooselist, args, 2);
  1175.  
  1176.     if (labelwidth > listwidth) {
  1177.     /* Make the list be centered.  Works because columnSpacing is 0 */
  1178.     XtSetArg(args[0], XtNinternalWidth,
  1179.          listintwid + (int)(labelwidth-listwidth)/2);
  1180.     XtSetValues(chooselist, args, 1);
  1181.     } else {
  1182.     XtSetArg(args[0], XtNwidth, listwidth);
  1183.     /* must also set label again to force box to redo layout */
  1184.     XtSetArg(args[1], XtNlabel, label);
  1185.     XtSetValues(chooselabel, args, 2);
  1186.     }
  1187.  
  1188.     return do_popup(choosepopup);
  1189. }
  1190.  
  1191. extern int
  1192. uims_do_selector_popup(void)
  1193. {
  1194.     /* We skip the zeroth selector, which is selector_uninitialized. */
  1195.     int t = choose_popup(sd_resources.selector_title, &selector_names[1]);
  1196.     if (t==0) return POPUP_DECLINE;
  1197.     return t;
  1198. }    
  1199.  
  1200.  
  1201. static String quantifier_names[] = {
  1202.     " 1 ", " 2 ", " 3 ", " 4 ", " 5 ", NULL};
  1203.  
  1204. extern int
  1205. uims_do_quantifier_popup(void)
  1206. {
  1207.     int t = choose_popup(sd_resources.quantifier_title, quantifier_names);
  1208.     if (t==0) return POPUP_DECLINE;
  1209.     return t;
  1210. }
  1211.  
  1212.  
  1213. static String empty_string = "";
  1214. static String *concept_popup_list = NULL;
  1215.  
  1216. extern int
  1217. uims_do_concept_popup(int kind)
  1218. {
  1219.     unsigned int i;
  1220.     unsigned int row, column;
  1221.     unsigned int maxrow, maxcolumn, entries;
  1222.     Arg args[1];
  1223.     int value;
  1224.  
  1225.     /* determine menu size */
  1226.     for (maxcolumn=0; concept_size_tables[kind][maxcolumn]>=0; maxcolumn++)
  1227.     ;
  1228.     maxrow = 0;
  1229.     for (i=0; i<maxcolumn; i++)
  1230.     if (maxrow < concept_size_tables[kind][i])
  1231.         maxrow = concept_size_tables[kind][i];
  1232.     entries = maxcolumn*maxrow;
  1233.     
  1234.     concept_popup_list =
  1235.     (String *) XtRealloc((char *)concept_popup_list,
  1236.                  entries*sizeof(String *));
  1237.  
  1238.     /* fill in the entries */
  1239.     i=0;
  1240.     for (row=0; row<maxrow; row++) {
  1241.     for (column=0; column<maxcolumn; column++) {
  1242.         if (row < concept_size_tables[kind][column])
  1243.         concept_popup_list[i] = concept_descriptor_table
  1244.             [ concept_offset_tables[kind][column]+row ].name;
  1245.         else
  1246.         concept_popup_list[i] = empty_string;
  1247.         i++;
  1248.     }
  1249.     }
  1250.  
  1251.     XtSetArg(args[0], XtNdefaultColumns, maxcolumn);
  1252.     XtSetValues(conceptlist, args, 1);
  1253.     XawListChange(conceptlist, concept_popup_list, entries, 0, TRUE);
  1254.     value = do_popup(conceptpopup);
  1255.  
  1256.     if (value) {
  1257.     value--;
  1258.     /* row and column are 0-based */
  1259.     row = value/maxcolumn;
  1260.     column = value%maxcolumn;
  1261.     if (row < concept_size_tables[kind][column]) /* not off the end? */
  1262.         return (column<<8) + row + 1;
  1263.     }
  1264.     return POPUP_DECLINE;
  1265. }
  1266.  
  1267. /* variables used by the next two routines */
  1268.  
  1269. static XawTextPosition *line_indexes = NULL; /* end position of each line */
  1270. static int line_count = 0;    /* size of line_indexes */
  1271. static XawTextBlock text_block;
  1272.  
  1273. /*
  1274.  * add a line to the text output area.
  1275.  * the_line does not have the trailing Newline in it and
  1276.  * is volitile, so we must copy it if we need it to stay around.
  1277.  */
  1278. extern void
  1279. uims_add_new_line(char the_line[])
  1280. {
  1281.     XawTextPosition prev_size = line_count ? line_indexes[line_count-1] : 0;
  1282.     XawTextPosition line_len, new_size;
  1283.     int status;
  1284.     Arg args[1];
  1285.  
  1286.     XawTextDisableRedisplay(txtwin);
  1287.  
  1288.     line_len = strlen(the_line);
  1289.     new_size = prev_size + line_len;
  1290.     line_count++;
  1291.     line_indexes =
  1292.     (XawTextPosition *)XtRealloc((char *)line_indexes,
  1293.                      line_count * sizeof(XawTextPosition*));
  1294.     line_indexes[line_count-1] = new_size + 1; /* 1 more for the newline */
  1295.  
  1296.     /* make text widget writable */
  1297.     XtSetArg(args[0], XtNeditType, XawtextEdit);
  1298.     XtSetValues(txtwin, args, 1);
  1299.     /* append new line */
  1300.     text_block.firstPos = 0;
  1301.     text_block.length = line_len;
  1302.     text_block.ptr = the_line;
  1303.     text_block.format = FMT8BIT;
  1304.     status = XawTextReplace(txtwin, prev_size, prev_size, &text_block);
  1305.     if (status != XawEditDone)
  1306.     (void) fprintf(stderr, "%s warning: text append returned %d\n",
  1307.                program_name, status);
  1308.     text_block.length = 1;
  1309.     text_block.ptr = "\n";
  1310.     status = XawTextReplace(txtwin, new_size, new_size, &text_block);
  1311.     if (status != XawEditDone)
  1312.     (void) fprintf(stderr, "%s warning: newline append returned %d\n",
  1313.                program_name, status);
  1314.     /* move to end to ensure we scroll this line onto the screen */
  1315.     XawTextSetInsertionPoint(txtwin, new_size);
  1316.     /* make text widget read-only again */
  1317.     XtSetArg(args[0], XtNeditType, XawtextRead);
  1318.     XtSetValues(txtwin, args, 1);
  1319. }
  1320.  
  1321. /*
  1322.  * Throw away all but the first n lines of the text output.
  1323.  * n = 0 means to erase the entire buffer.
  1324.  */
  1325. extern void
  1326. uims_reduce_line_count(int n)
  1327. {
  1328.     XawTextPosition prev_size = line_count ? line_indexes[line_count-1] : 0;
  1329.     XawTextPosition new_size;
  1330.     int status;
  1331.     Arg args[1];
  1332.  
  1333.     if (n >= line_count)
  1334.     return;            /* should never happen */
  1335.     new_size = n==0 ? 0 : line_indexes[n-1];
  1336.  
  1337.     XawTextDisableRedisplay(txtwin);
  1338.  
  1339.     /* make text widget writable */
  1340.     XtSetArg(args[0], XtNeditType, XawtextEdit);
  1341.     XtSetValues(txtwin, args, 1);
  1342.     /* delete the text */
  1343.     text_block.length = 0;
  1344.     status = XawTextReplace(txtwin, new_size, prev_size, &text_block);
  1345.     if (status != XawEditDone)
  1346.     (void) fprintf(stderr, "%s warning: text delete returned %d\n",
  1347.                program_name, status);
  1348.     /* make text widget read-only again */
  1349.     XtSetArg(args[0], XtNeditType, XawtextRead);
  1350.     XtSetValues(txtwin, args, 1);
  1351.  
  1352.     line_count = n;
  1353.     line_indexes =
  1354.     (XawTextPosition *)XtRealloc((char *)line_indexes,
  1355.                      line_count * sizeof(XawTextPosition *));
  1356. }
  1357.  
  1358.  
  1359. extern void
  1360. uims_terminate(void)
  1361. {
  1362.     /* if uims_preinitialize was called, close down the window system */
  1363.     if (program_name)
  1364.     XtDestroyApplicationContext(xtcontext);
  1365. }
  1366.